package com.un.ebs.workflow.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.un.ebs.core.exception.BusinessEntityNotFoundException;
import com.un.ebs.core.exception.BusinessException;
import com.un.ebs.core.util.StringUtils;
import com.un.ebs.sys.domain.UserGroup;
import com.un.ebs.sys.mapper.UserGroupMapper;
import com.un.ebs.sys.service.UserGroupService;
import com.un.ebs.workflow.domain.Workflow;
import com.un.ebs.workflow.domain.WorkflowNode;
import com.un.ebs.workflow.domain.WorkflowNodeExt;
import com.un.ebs.workflow.domain.WorkflowNodeGateway;
import com.un.ebs.workflow.dto.*;
import com.un.ebs.workflow.enums.GatewayTypeEnum;
import com.un.ebs.workflow.enums.NodeTypeEnum;
import com.un.ebs.workflow.mapper.WorkflowMapper;
import com.un.ebs.workflow.mapper.WorkflowNodeExtMapper;
import com.un.ebs.workflow.mapper.WorkflowNodeGatewayMapper;
import com.un.ebs.workflow.mapper.WorkflowNodeMapper;
import com.un.ebs.workflow.service.WorkflowService;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * (Workflow)表服务实现类
 *
 * @author liubo
 * @since 2020-08-23 09:56:25
 */
@Service
public class WorkflowServiceImpl extends ServiceImpl<WorkflowMapper, Workflow> implements WorkflowService {

    @Resource
    private WorkflowNodeMapper workflowNodeMapper;

    @Resource
    private WorkflowNodeGatewayMapper workflowNodeGatewayMapper;

    @Resource
    private UserGroupMapper userGroupMapper;

    @Resource
    private UserGroupService userGroupService;

    @Resource
    private WorkflowNodeExtMapper workflowNodeExtMapper;

    @Override
    public void update(WorkflowUpdateDto req) {
        Workflow obj;
        WorkflowNode startNode = null;
        WorkflowNode endNode = null;
        UserGroup usergroup = userGroupService.queryOrCreate("示例用户组");
        if (StringUtils.isNullOrEmpty(req.getId())) {
            obj = new Workflow();
            startNode = new WorkflowNode();
            startNode.setName("节点 1");
            startNode.setType(NodeTypeEnum.Manual_Audit);

            endNode = new WorkflowNode();
            endNode.setName("节点 2");
            endNode.setType(NodeTypeEnum.Manual_Audit);

        } else {
            obj = baseMapper.selectById(req.getId());
            if (obj == null) {
                throw new BusinessEntityNotFoundException(req.getId(), "流程");
            }
        }

        obj.setCode(req.getCode());
        obj.setName(req.getName());
        obj.setIsAutoComplete(req.getIsAutoComplete());
        obj.insertOrUpdate();

        if (startNode != null && endNode != null) {
            startNode.setWorkflowId(obj.getId());
            startNode.setUserGroupId(usergroup.getId());
            startNode.insertOrUpdate();

            endNode.setWorkflowId(obj.getId());
            endNode.setUserGroupId(usergroup.getId());
            endNode.insertOrUpdate();

            WorkflowNodeGateway gateway = new WorkflowNodeGateway();
            gateway.setPrevNodeId(startNode.getId());
            gateway.setNextNodeId(endNode.getId());
            gateway.setGatewayType(GatewayTypeEnum.Default);
            gateway.setWorkflowId(obj.getId());
            gateway.insertOrUpdate();
        }
    }

    @Override
    public void updateNode(WorkflowNodeUpdateDto req) {
        WorkflowNode obj;
        if (StringUtils.isNullOrEmpty(req.getId())) {
            obj = new WorkflowNode();
        } else {
            obj = workflowNodeMapper.selectById(req.getId());
            if (obj == null) {
                throw new BusinessEntityNotFoundException(req.getId(), "流程节点");
            }
        }

        obj.setName(req.getName());
        obj.setWorkflowId(req.getWorkflowId());
        obj.setUserGroupId(req.getUserGroupId());
        obj.setType(req.getNodeType());
        obj.insertOrUpdate();
    }

    @Override
    public void updateGateway(WorkflowNodeGatewayUpdateDto req) {
        WorkflowNodeGateway obj;
        if (StringUtils.isNullOrEmpty(req.getId())) {
            obj = new WorkflowNodeGateway();
        } else {
            obj = workflowNodeGatewayMapper.selectById(req.getId());
            if (obj == null) {
                throw new BusinessEntityNotFoundException(req.getId(), "流程网关");
            }
        }

        obj.setPrevNodeId(req.getPrevNodeId());
        obj.setNextNodeId(req.getNextNodeId());
        obj.setGatewayType(req.getGatewayType());
        obj.setExpression(req.getExpression());
        obj.setWorkflowId(req.getWorkflowId());

        if (StringUtils.isNullOrEmpty(req.getPrevNodeId()) && req.getGatewayType() != GatewayTypeEnum.Start) {
            throw new BusinessException(String.format("当前一节点为空时，网关类型应该是【%s】", GatewayTypeEnum.Start.getDesc()));
        }
        if (StringUtils.isNullOrEmpty(req.getNextNodeId()) && req.getGatewayType() != GatewayTypeEnum.End) {
            throw new BusinessException(String.format("当下一节点为空时，网关类型应该是【%s】", GatewayTypeEnum.End.getDesc()));
        }
        obj.insertOrUpdate();
    }

    @Override
    public void delete(String id) {
        baseMapper.deleteById(id);
    }

    @Override
    public void deleteNode(String id) {
        workflowNodeMapper.deleteById(id);
    }

    @Override
    public void deleteGateway(String id) {
        workflowNodeGatewayMapper.deleteById(id);
    }

    @Override
    public IPage<Workflow> query(String searchText, int pageSize, int pageIndex) {
        LambdaQueryWrapper<Workflow> lq = Wrappers.lambdaQuery();
        lq.eq(Workflow::getIsDelete, false);
        if (!StringUtils.isNullOrEmpty(searchText)) {
            lq.like(Workflow::getCode, searchText).or().like(Workflow::getName, searchText);
        }

        Page<Workflow> page = new Page<>(pageIndex, pageSize);
        return baseMapper.selectPage(page, lq);
    }

    @Override
    public Workflow queryById(String id) {
        return baseMapper.selectById(id);
    }

    @Override
    public WorkflowNodeVo queryAllNodeById(String workflowId) {
        LambdaQueryWrapper<WorkflowNodeGateway> lq = Wrappers.lambdaQuery();
        lq.eq(WorkflowNodeGateway::getWorkflowId, workflowId);
        lq.isNull(WorkflowNodeGateway::getPrevNodeId);
        lq.eq(WorkflowNodeGateway::getGatewayType, GatewayTypeEnum.Start);
        WorkflowNodeGateway startGateway = workflowNodeGatewayMapper.selectOne(lq);
        if (startGateway == null) {
            throw new BusinessException("没有找到首节点。");
        }

        WorkflowNode firstNode = workflowNodeMapper.selectById(startGateway.getNextNodeId());
        WorkflowNodeVo node = new WorkflowNodeVo();
        BeanUtils.copyProperties(firstNode, node);
        if (!StringUtils.isNullOrEmpty(firstNode.getUserGroupId())) {
            node.setUserGroupName(userGroupMapper.selectById(firstNode.getUserGroupId()).getName());
        }

        if (!StringUtils.isNullOrEmpty(startGateway.getNextNodeId())) {
            WorkflowNodeGateway first = queryFirstGateway(workflowId);
            node.setNextGateway(queryGateway(startGateway.getWorkflowId(), first.getNextNodeId()));
        }

        return node;
    }

    @Override
    public List<WorkflowNodeExt> queryNodes(String workflowId) {
        LambdaQueryWrapper<WorkflowNodeExt> lq = Wrappers.lambdaQuery();
        lq.eq(WorkflowNodeExt::getWorkflowId, workflowId);
        lq.orderByAsc(WorkflowNodeExt::getCreateTime);
        return workflowNodeExtMapper.selectList(lq);
    }

    @Override
    public List<WorkflowNodeGateway> queryGatewayByWorkFlowId(String workflowId) {
        LambdaQueryWrapper<WorkflowNodeGateway> lq = Wrappers.lambdaQuery();
        lq.eq(WorkflowNodeGateway::getWorkflowId, workflowId);
        lq.orderByAsc(WorkflowNodeGateway::getCreateTime);
        return workflowNodeGatewayMapper.selectList(lq);
    }

    @Override
    public WorkflowNodeExt queryNodeById(String nodeId) {
        return workflowNodeExtMapper.selectById(nodeId);
    }

    @Override
    public WorkflowNodeGateway queryFirstGateway(String workflowId) {
        LambdaQueryWrapper<WorkflowNodeGateway> lq = Wrappers.lambdaQuery();
        lq.eq(WorkflowNodeGateway::getWorkflowId, workflowId);
        lq.isNull(WorkflowNodeGateway::getPrevNodeId);
        lq.eq(WorkflowNodeGateway::getGatewayType, GatewayTypeEnum.Start);
        return workflowNodeGatewayMapper.selectOne(lq);
    }

    private @NotNull List<WorkflowGatewayVo> queryGateway(String workflowId, String prevNodeId) {
        List<WorkflowGatewayVo> ret = new ArrayList<>();
        LambdaQueryWrapper<WorkflowNodeGateway> lq = Wrappers.lambdaQuery();
        lq.eq(WorkflowNodeGateway::getWorkflowId, workflowId);
        lq.eq(WorkflowNodeGateway::getPrevNodeId, prevNodeId);
        List<WorkflowNodeGateway> list = workflowNodeGatewayMapper.selectList(lq);
        for (WorkflowNodeGateway gateway : list) {
            if (StringUtils.isNullOrEmpty(gateway.getNextNodeId())) {
                break;
            }

            WorkflowGatewayVo obj = new WorkflowGatewayVo();
            BeanUtils.copyProperties(gateway, obj);

            if (!StringUtils.isNullOrEmpty(gateway.getNextNodeId())) {
                Optional<WorkflowNodeVo> nextNode = queryNextNodes(workflowId, gateway.getNextNodeId()).stream().findFirst();
                if (nextNode.isPresent()) {
                    //queryNextNodes(workflowId, gateway.getNextNodeId())
                    obj.setNextNode(nextNode.get());
                }

            }
            ret.add(obj);
        }
        return ret;
    }

    @Override
    public WorkflowNodeGateway queryGateway(String id) {
        return workflowNodeGatewayMapper.selectById(id);
    }

    @Override
    public WorkflowNode queryPrevNode(String workflow, String currNodeId) {
        return null;
    }

    @Override
    public List<WorkflowNodeVo> queryNextNodes(String workflowId, String currNodeId) {
        if (StringUtils.isNullOrEmpty(currNodeId)) {
            return new ArrayList<>();
        }

        LambdaQueryWrapper<WorkflowNodeGateway> lq = Wrappers.lambdaQuery();
        lq.eq(WorkflowNodeGateway::getNextNodeId, currNodeId);
        List<String> ids = workflowNodeGatewayMapper.selectList(lq).stream().map(s -> s.getNextNodeId()).collect(Collectors.toList());
        if (StringUtils.isNullOrEmpty(ids)) {
            return new ArrayList<>();
        }

        List<WorkflowNodeVo> list = workflowNodeMapper.selectBatchIds(ids).stream().map(s -> {
            return convertToVo(s);
        }).collect(Collectors.toList());

        //根据下级网关，加载下级节点
        for (WorkflowNodeVo node : list) {
            node.setNextGateway(queryGateway(workflowId, node.getId()));
        }

        return list;

    }

    private @NotNull WorkflowNodeVo convertToVo(WorkflowNode obj) {
        WorkflowNodeVo ret = new WorkflowNodeVo();
        BeanUtils.copyProperties(obj, ret);
        if (!StringUtils.isNullOrEmpty(obj.getUserGroupId())) {
            ret.setUserGroupName(userGroupMapper.selectById(obj.getUserGroupId()).getName());
        }
        return ret;
    }

}